using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Drawing;
using System.Configuration;


using BizElements.BusinessLayer;

namespace BizElements.Web
{
	/// <summary>
	/// Label control bound to a business class property.
	/// </summary>
	[DefaultProperty("Text"),
	ToolboxData("<{0}:BoundLabel runat=server></{0}:BoundLabel>")]
	public class BoundLabel : System.Web.UI.WebControls.Label, IBoundControl, IValidator
	{
        Label errorLbl = new Label();

		#region Fields.

		IBindableField bizField;
        Color errorColor = Color.Red;
		ErrorLocation errorLocation = ErrorLocation.Below;

		#endregion

		#region Constructors.

		/// <summary>
		/// Initializes a new instance of the <see cref="BoundLabel"/> class.
		/// </summary>
		public BoundLabel()
		{
		}

		#endregion

        #region OnInit.

        /// <summary>
        /// Raises the <b>Init</b> event.
        /// </summary>
        /// <param name="e">An <b>EventArgs</b> object that contains the event data.</param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            AddMyselfToParentPageValidators();
        }

        private void AddMyselfToParentPageValidators()
		{
			this.Page.Validators.Add(this);
        }

        #endregion

        #region Control properties.

        bool fieldCaptionIsDefaultToolTip = true;

        /// <summary>
        /// Gets or sets whether the caption of the bound field is used as default tooltip.
        /// </summary>
        /// <value><b>true</b> if field caption is default tooltop; <b>false</b> otherwise. Default is <b>true</b>.</value>
        [Bindable(false)]
        [Category("Behavior")]
        [DefaultValue(true)]
        [Description("Whether the caption of the bound field is used as default tooltip.")]
        public virtual bool FieldCaptionIsDefaultToolTip
        {
            get { return this.fieldCaptionIsDefaultToolTip; }
            set { this.fieldCaptionIsDefaultToolTip = value; }
        }

        #endregion

        #region Error properties.

        /// <summary>
        /// Gets or sets the CSS Class name applied to the error label.
        /// </summary>
        [Bindable(false), Category("Appearance"), DefaultValue(null),
        Description("CSS Class name applied to the error label.")]
        public virtual string ErrorCss
        {
            get { return this.errorLbl.CssClass; }
            set { this.errorLbl.CssClass = value; }
        }

        /// <summary>
        /// Gets or sets the color of the error text.
        /// </summary>
        [Bindable(false), Category("Appearance"), DefaultValue(typeof(Color), "Red"),
        Description("Color of the error text.")]
        [TypeConverter(typeof(WebColorConverter))]
        public virtual Color ErrorColor
        {
            get { return this.errorColor; }
            set { this.errorColor = value; }
        }

        /// <summary>
        /// Gets or sets the error text displayed in the error label or in the page's validation summary. 
        /// Usually set programmatically.
        /// </summary>
        [Bindable(false), Category("Appearance"),
        Description("Error text displayed in the error label or in the page's validation summary. Usually set programmatically.")]
        [DefaultValue("")]
        public virtual string ErrorText
        {
            get { return this.errorLbl.Text; }
            set { this.errorLbl.Text = value; }
        }

        /// <summary>
        /// Gets or sets the indicator placed by the control if it contains an invalid value. 
        /// Displayed only when the error text is displayed in the validation summary.
        /// </summary>
        [Bindable(false), Category("Appearance"), DefaultValue("*"),
        Description("Indicator placed by the control if it contains an invalid value. Displayed only when the error text is displayed in the validation summary.")]
        public virtual string ErrorIndicator
        {
            get { return "*"; }
            set { }
        }

        /// <summary>
        /// Gets or sets the value which specifies where the error text is located.
        /// </summary>
        [Bindable(false), Category("Appearance"), DefaultValue(typeof(ErrorLocation), "Below"),
        Description("Specifies where the error text is located.")]
        public virtual ErrorLocation ErrorLocation
        {
            get { return this.errorLocation; }
            set { this.errorLocation = value; }
        }

		#endregion

		#region IBoundControl.

		/// <summary>
		/// Has no effect. <b>BoundLabel</b> is always read-only.
		/// </summary>
        [Bindable(false), Category("Behavior"), DefaultValue(typeof(FieldAccessMode), "ReadOnly"),
		Description("Indicates whether the contents of the control can be changed.")]
		public FieldAccessMode AccessMode
		{
			get {return FieldAccessMode.ReadOnly;}
			set {}
		}

		/// <summary>
		/// Gets or sets the business class' property to which the control is bound. Set programmatically.
		/// </summary>
		[Description("Business class' property to which the control is bound. Set programmatically.")]
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public virtual IBindableField BusinessField
		{
			get {return this.bizField;}
			set {this.bizField = value;}
		}

		/// <summary>
		/// Appends all errors in the collection to the <see cref="ErrorText"/>.
		/// </summary>
		/// <param name="rules">Collection of broken rules.</param>
		/// <param name="formatter">The <see cref="IMessageFormatter"/> object used to format the messages contained in the collection.</param>
		public virtual void AppendError(BusinessRuleCollection rules, IMessageFormatter formatter)
		{
			BusinessRuleCollection brokenRulesForThisControl = rules.GetRulesForField(this.BusinessField.BindingName, true);
			this.ErrorText += brokenRulesForThisControl.ToString(formatter) + " ";
		}

		/// <summary>
		/// Clears errors. Same as setting the <see cref="ErrorText"/> to empty string.
		/// </summary>
		public virtual void ClearError()
		{
			this.ErrorText = "";
		}

		#endregion

		#region IValidator.

		/// <summary>
		/// Gets the value contained in the <see cref="ErrorText"/> property if a validation summary has been specified as location for errors.
		/// </summary>
		string IValidator.ErrorMessage
		{
			get 
			{
				if (this.errorLocation == ErrorLocation.ValidationSummary)
					return this.ErrorText;
				else
					return "";
			}
			set 
			{				
			}
		}		

		/// <summary>
		/// Does nothing. Validation logic is performed elsewhere (eg. business class).
		/// </summary>
		void IValidator.Validate()
		{
		}

		/// <summary>
		/// Gets a value which indicates whether an the <see cref="ErrorText"/> property contains error description.
		/// </summary>
		bool IValidator.IsValid
		{
			get
			{
				if (this.ErrorText == null  ||  this.ErrorText.Trim() == "")
					return true;
				else
					return false;
			}
			set 
			{
			}
		}

		#endregion

		#region Render.

		/// <summary>
		/// Sends server control content to a provided <see cref="HtmlTextWriter"/> object, which writes the content to be rendered on the client.
		/// </summary>
		/// <param name="output">The <b>HtmlTextWriter</b> object that receives the server control content.</param>
		protected override void Render(HtmlTextWriter output)
		{
            if (this.FieldCaptionIsDefaultToolTip && string.IsNullOrEmpty(this.ToolTip) && this.bizField != null)
                this.ToolTip = bizField.Caption;

			base.Render(output);
            RenderErrorMessage(output);
		}

        private void RenderErrorMessage(HtmlTextWriter output)
        {
            if (this.errorLbl.Text != null && this.errorLbl.Text.Trim() != "")
            {
                this.errorLbl.ForeColor = this.ErrorColor;
                this.errorLbl.EnableViewState = false;
                switch (this.errorLocation)
                {
                    case ErrorLocation.Below:
                        output.Write("<br />");
                        break;

                    case ErrorLocation.Right:
                        output.Write("&nbsp;");
                        break;

                    case ErrorLocation.ValidationSummary:
                        output.Write("&nbsp;");
                        break;
                }

                this.errorLbl.RenderControl(output);
            }
        }

		#endregion

        /// <summary>Gets the name of the control property which is bound two-way to a business object field: <b>Text</b></summary>
        public string TwoWayBoundProperty
        {
            get { return "Text"; }
        }

        /// <summary>Returns <b>null</b>.</summary>
        public string[] OneWayBoundProperties
        {
            get { return null; }
        }

        /// <summary>Gets error label control which displays errors associated with the given field.</summary>
        [Browsable(false)]
        public ITextControl ErrorLabel
        {
            get { return this.errorLbl; }
        }

        /// <summary>Not implemented. Returns <b>null</b>.</summary>
        [Browsable(false)]
        ITextControl IBoundControl.CaptionLabel
        {
            get { return null; }
        }

        /// <summary>Not implemented. Returns <b>null</b>.</summary>
        [Browsable(false)]
        ITextControl IBoundControl.TooltipLabel
        {
            get { return null; }
        }

        /// <summary>Not implemented. Returns <b>null</b>.</summary>
        [Browsable(false)]
        Control IBoundControl.RequiredFieldIndicatorControl
        {
            get { return null; }
        }
	}
}